package cn.iocoder.yudao.module.asasc.service.campaign;

import cn.iocoder.yudao.module.asasc.common.AsaConstant;
import cn.iocoder.yudao.module.asasc.controller.admin.campaign.vo.CampaignDataReqDTO;
import cn.iocoder.yudao.module.asasc.controller.admin.campaign.vo.CampaignDataSaveReqVO;
import cn.iocoder.yudao.module.asasc.controller.admin.campaign.vo.CampaignGrandTotalsSaveReqVO;
import cn.iocoder.yudao.module.asasc.controller.admin.openapi.vo.CampaignDataUnionVO;
import cn.iocoder.yudao.module.asasc.controller.admin.openapi.vo.CampaignUnionRespVO;
import cn.iocoder.yudao.module.asasc.dal.dataobject.campaign.AsaAppConfigDO;
import cn.iocoder.yudao.module.asasc.dal.redis.AsaTokenRedisDAO;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Validated
@Slf4j
public class CampaignDataApiServiceImpl implements CampaignDataApiService {
    @Resource
    private AsaTokenRedisDAO asaTokenRedisDAO;

    @Resource
    private CampaignDataService campaignDataService;
    @Resource
    private CampaignGrandTotalsService campaignGrandTotalsService;

    private static @NotNull CampaignDataReqDTO getCampaignDataReqDTO(Long adamId, String strDate, String endDate) {
        // 创建并设置 CampaignDataReqDTO 对象
        CampaignDataReqDTO reqDTO = new CampaignDataReqDTO();
        reqDTO.setStartTime(strDate);
        reqDTO.setEndTime(endDate);
        reqDTO.setGranularity("DAILY");
        reqDTO.setGroupBy(List.of("countryOrRegion"));
        reqDTO.setTimeZone("ORTZ");
        reqDTO.setReturnRecordsWithNoMetrics(true);
        reqDTO.setReturnRowTotals(true);
        reqDTO.setReturnGrandTotals(true);

        CampaignDataReqDTO.Selector selector = new CampaignDataReqDTO.Selector();
        CampaignDataReqDTO.Selector.OrderBy orderBy = new CampaignDataReqDTO.Selector.OrderBy();
        orderBy.setField("countryOrRegion");
        orderBy.setSortOrder("ASCENDING");
        selector.setOrderBy(List.of(orderBy));

        CampaignDataReqDTO.Selector.Condition condition = new CampaignDataReqDTO.Selector.Condition();
        condition.setField("adamId");
        condition.setOperator("IN");
        condition.setValues(List.of(String.valueOf(adamId)));
        selector.setConditions(List.of(condition));

        CampaignDataReqDTO.Selector.Pagination pagination = new CampaignDataReqDTO.Selector.Pagination();
        pagination.setOffset(0);
        pagination.setLimit(1000);
        selector.setPagination(pagination);

        reqDTO.setSelector(selector);
        return reqDTO;
    }

    /**
     * 获取某个账号下某个应用的数据
     *
     * @param configDO
     * @param strDate
     * @param endDate
     * @return
     */
    @Override
    public CampaignUnionRespVO getDailyCampaigns(AsaAppConfigDO configDO, String strDate, String endDate) {
        try {
            CampaignUnionRespVO campaignRespVO = new CampaignUnionRespVO();
            CampaignDataReqDTO reqDTO = getCampaignDataReqDTO(configDO.getAdamId(), strDate, endDate);

            HttpClient client = HttpClient.newHttpClient();
            Gson gson = new Gson();
            String requestBody = gson.toJson(reqDTO);

            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(AsaConstant.CAMPAIGNS_API_URL))
                    .timeout(Duration.ofSeconds(10))
                    .header("Authorization", String.format("Bearer %s", asaTokenRedisDAO.getToken(configDO)))
                    .header("X-AP-Context", String.format("orgId=%s", configDO.getOrgId()))
                    .header("Content-Type", "application/json")
                    .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                    .build();

            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println("response: " + response.body());
            if (response.statusCode() == 200) {
                JsonObject rootNode = JsonParser.parseString(response.body()).getAsJsonObject();
                JsonObject reportingDataResponse = rootNode.getAsJsonObject("data")
                        .getAsJsonObject("reportingDataResponse");

                // 手动解析 JSON 数据
                CampaignDataUnionVO dailyCampaigns = new CampaignDataUnionVO();
                dailyCampaigns.setRow(parseRows(reportingDataResponse.getAsJsonArray("row")));
                dailyCampaigns.setGrandTotals(parseGrandTotals(reportingDataResponse.getAsJsonObject("grandTotals")));

                List<CampaignDataSaveReqVO> campaignDataReqVOS = getCampaignDataReqVOS(dailyCampaigns);
                campaignRespVO.setCampaigns(campaignDataReqVOS);

                if (strDate.equals(endDate)) {
                    Map<String, CampaignGrandTotalsSaveReqVO> dataMap = Maps.newConcurrentMap();
                    dataMap.put(strDate, getCampaignGrandTotalsReqVO(strDate, dailyCampaigns));
                    campaignRespVO.setGrandTotalsMap(dataMap);
                } else {
                    campaignRespVO.setGrandTotalsMap(getCampaignGrandTotalsReqVO(campaignDataReqVOS));
                }

                return campaignRespVO;
            } else {
                // Handle non-200 responses
                throw new RuntimeException("Failed to fetch campaign data: " + response.body());
            }
        } catch (Exception e) {
            throw new RuntimeException("Error during HTTP request", e);
        }
    }

    @Override
    public Map<String, Object> postDailyCampaigns(String body) {
        Map<String, Object> result = new HashMap<>();
        try {
            CampaignUnionRespVO respVO = new CampaignUnionRespVO();
            JsonObject rootNode = JsonParser.parseString(body).getAsJsonObject();
            JsonObject reportingDataResponse = rootNode.getAsJsonObject("data").getAsJsonObject("reportingDataResponse");

            // 手动解析 JSON 数据
            CampaignDataUnionVO dailyCampaigns = new CampaignDataUnionVO();
            dailyCampaigns.setRow(parseRows(reportingDataResponse.getAsJsonArray("row")));
            dailyCampaigns.setGrandTotals(parseGrandTotals(reportingDataResponse.getAsJsonObject("grandTotals")));

            List<CampaignDataSaveReqVO> campaignDataReqVOS = getCampaignDataReqVOS(dailyCampaigns);
            respVO.setCampaigns(campaignDataReqVOS);
            respVO.setGrandTotalsMap(getCampaignGrandTotalsReqVO(campaignDataReqVOS));

            respVO.getCampaigns().stream()
                    .filter(Objects::nonNull)
                    .filter(a -> !Objects.isNull(a.getImpressions()))
                    .forEach(a -> campaignDataService.createCampaignData(a));

            respVO.getGrandTotalsMap().forEach((k, v) -> campaignGrandTotalsService.createCampaignGrandTotals(v));

            log.info("[新增广告系列数据 ({}) 条]", respVO.getCampaigns().size());
            log.info("[新增广告系列汇总数据 ({}) 条]", respVO.getGrandTotalsMap().size());
            //返回具体条数
            result.put("success", true);
            result.put("message", "数据上报成功");
            result.put("campaigns", respVO.getCampaigns().size());
            result.put("grandTotals", respVO.getGrandTotalsMap().size());
        } catch (Exception e) {
            String errorMsg;
            if (!Objects.isNull(e.getMessage()) && e.getMessage().contains("unq_date_country_campaign")) {
                errorMsg = e.getMessage().substring(e.getMessage().lastIndexOf("Duplicate entry"));
                errorMsg = "Campaign 数据已存在：" + errorMsg;
                result.put("success", false);
                result.put("message", errorMsg);
                log.error("postDailyCampaigns error: {}", errorMsg);
            } else if (!Objects.isNull(e.getMessage()) && e.getMessage().contains("unq_date_country_campaign_grand")) {
                errorMsg = e.getMessage().substring(e.getMessage().lastIndexOf("Duplicate entry"));
                errorMsg = "Campaign GrandTotal 数据已存在：" + errorMsg;
                result.put("success", false);
                result.put("message", errorMsg);
                log.error("postDailyCampaigns error: {}", errorMsg);
            } else {
                result.put("success", false);
                result.put("message", e.getMessage());
                e.printStackTrace();
            }
        }
        return result;
    }

    private List<CampaignDataUnionVO.Row> parseRows(JsonElement rowsElement) {
        // 手动解析 rows 数据
        List<CampaignDataUnionVO.Row> rows = new ArrayList<>();
        for (JsonElement rowElement : rowsElement.getAsJsonArray()) {
            JsonObject rowObject = rowElement.getAsJsonObject();
            CampaignDataUnionVO.Row row = new CampaignDataUnionVO.Row();
            // 解析 row 的各个字段
            row.setMetadata(parseMetadata(rowObject.getAsJsonObject("metadata")));
            row.setGranularity(parseGranularity(rowObject.getAsJsonArray("granularity")));
            rows.add(row);
        }
        return rows;
    }

    private CampaignDataUnionVO.Row.Metadata parseMetadata(JsonObject object) {
        // 手动解析 metadata 数据
        CampaignDataUnionVO.Row.Metadata metadata = new CampaignDataUnionVO.Row.Metadata();
        metadata.setCampaignId(object.get("campaignId").getAsLong());
        metadata.setCampaignName(object.get("campaignName").getAsString());
        metadata.setDeleted(object.get("deleted").getAsBoolean());
        metadata.setCampaignStatus(object.get("campaignStatus").getAsString());
        JsonObject appObject = object.getAsJsonObject("app");
        CampaignDataUnionVO.Row.Metadata.App app = new CampaignDataUnionVO.Row.Metadata.App();
        app.setAppName(appObject.get("appName").getAsString());
        app.setAdamId(appObject.get("adamId").getAsLong());
        metadata.setApp(app);
        metadata.setServingStatus(object.get("servingStatus").getAsString());
        metadata.setServingStateReasons(object.get("servingStateReasons").isJsonNull() ? null
                : object.get("servingStateReasons").getAsString());
        metadata.setCountriesOrRegions(parseStringArray(object.getAsJsonArray("countriesOrRegions")));
        metadata.setModificationTime(object.get("modificationTime").getAsString());
        metadata.setTotalBudget(object.get("totalBudget").isJsonNull() ? null
                : object.get("totalBudget").getAsString());
        JsonObject dailyBudgetObject = object.getAsJsonObject("dailyBudget");
        CampaignDataUnionVO.Row.Metadata.DailyBudget dailyBudget = new CampaignDataUnionVO.Row.Metadata.DailyBudget();
        dailyBudget.setAmount(dailyBudgetObject.get("amount").getAsString());
        dailyBudget.setCurrency(dailyBudgetObject.get("currency").getAsString());
        metadata.setDailyBudget(dailyBudget);
        metadata.setDisplayStatus(object.get("displayStatus").getAsString());
        metadata.setSupplySources(parseStringArray(object.getAsJsonArray("supplySources")));
        metadata.setAdChannelType(object.get("adChannelType").getAsString());
        metadata.setOrgId(object.get("orgId").getAsLong());
        metadata.setCountryOrRegionServingStateReasons(parseCountryOrRegionServingStateReasons(
                object.getAsJsonObject("countryOrRegionServingStateReasons")));
        metadata.setBillingEvent(object.get("billingEvent").getAsString());
        metadata.setCountryOrRegion(object.get("countryOrRegion").getAsString());
        return metadata;
    }

    private List<CampaignDataUnionVO.Row.Granularity> parseGranularity(JsonElement element) {
        // 手动解析 granularity 数据
        List<CampaignDataUnionVO.Row.Granularity> granularities = new ArrayList<>();
        for (JsonElement granElement : element.getAsJsonArray()) {
            JsonObject granObject = granElement.getAsJsonObject();
            CampaignDataUnionVO.Row.Granularity granularity = new CampaignDataUnionVO.Row.Granularity();
            granularity.setDate(granObject.get("date").getAsString());
            if (!granObject.has("impressions")) {
                continue;
            }
            granularity.setImpressions(granObject.get("impressions").getAsInt());
            granularity.setTaps(granObject.get("taps").getAsInt());
            granularity.setInstalls(granObject.get("installs").getAsInt());
            granularity.setNewDownloads(granObject.get("newDownloads").getAsInt());
            granularity.setRedownloads(granObject.get("redownloads").getAsInt());
            granularity.setLatOnInstalls(granObject.get("latOnInstalls").getAsInt());
            granularity.setLatOnInstalls(granObject.get("latOnInstalls").getAsInt());
            granularity.setLatOffInstalls(granObject.get("latOffInstalls").getAsInt());
            granularity.setTtr(granObject.get("ttr").getAsDouble());
            JsonObject avgCPAObject = granObject.getAsJsonObject("avgCPA");
            CampaignDataUnionVO.Amount avgCPA = new CampaignDataUnionVO.Amount();
            avgCPA.setAmount(avgCPAObject.get("amount").getAsString());
            avgCPA.setCurrency(avgCPAObject.get("currency").getAsString());
            granularity.setAvgCPA(avgCPA);
            JsonObject avgCPTObject = granObject.getAsJsonObject("avgCPT");
            CampaignDataUnionVO.Amount avgCPT = new CampaignDataUnionVO.Amount();
            avgCPT.setAmount(avgCPTObject.get("amount").getAsString());
            avgCPT.setCurrency(avgCPTObject.get("currency").getAsString());
            granularity.setAvgCPT(avgCPT);
            JsonObject avgCPMObject = granObject.getAsJsonObject("avgCPM");
            CampaignDataUnionVO.Amount avgCPM = new CampaignDataUnionVO.Amount();
            avgCPM.setAmount(avgCPMObject.get("amount").getAsString());
            avgCPM.setCurrency(avgCPMObject.get("currency").getAsString());
            granularity.setAvgCPM(avgCPM);
            JsonObject localSpendObject = granObject.getAsJsonObject("localSpend");
            CampaignDataUnionVO.Amount localSpend = new CampaignDataUnionVO.Amount();
            localSpend.setAmount(localSpendObject.get("amount").getAsString());
            localSpend.setCurrency(localSpendObject.get("currency").getAsString());
            granularity.setLocalSpend(localSpend);
            granularity.setConversionRate(granObject.get("conversionRate").getAsDouble());
            granularities.add(granularity);
        }
        return granularities;
    }

    private CampaignDataUnionVO.GrandTotals parseGrandTotals(JsonObject object) {
        // 手动解析 grandTotals 数据
        CampaignDataUnionVO.GrandTotals grandTotals = new CampaignDataUnionVO.GrandTotals();
        CampaignDataUnionVO.GrandTotals.Total total = new CampaignDataUnionVO.GrandTotals.Total();
        total.setImpressions(object.getAsJsonObject("total").get("impressions").getAsInt());
        total.setTaps(object.getAsJsonObject("total").get("taps").getAsInt());
        total.setInstalls(object.getAsJsonObject("total").get("installs").getAsInt());
        total.setNewDownloads(object.getAsJsonObject("total").get("newDownloads").getAsInt());
        total.setRedownloads(object.getAsJsonObject("total").get("redownloads").getAsInt());
        total.setLatOnInstalls(object.getAsJsonObject("total").get("latOnInstalls").getAsInt());
        total.setLatOffInstalls(object.getAsJsonObject("total").get("latOffInstalls").getAsInt());
        total.setTtr(object.getAsJsonObject("total").get("ttr").getAsDouble());
        JsonObject avgCPAObject = object.getAsJsonObject("total").getAsJsonObject("avgCPA");
        CampaignDataUnionVO.Amount avgCPA = new CampaignDataUnionVO.Amount();
        avgCPA.setAmount(avgCPAObject.get("amount").getAsString());
        avgCPA.setCurrency(avgCPAObject.get("currency").getAsString());
        total.setAvgCPA(avgCPA);
        JsonObject avgCPTObject = object.getAsJsonObject("total").getAsJsonObject("avgCPT");
        CampaignDataUnionVO.Amount avgCPT = new CampaignDataUnionVO.Amount();
        avgCPT.setAmount(avgCPTObject.get("amount").getAsString());
        avgCPT.setCurrency(avgCPTObject.get("currency").getAsString());
        total.setAvgCPT(avgCPT);
        JsonObject avgCPMObject = object.getAsJsonObject("total").getAsJsonObject("avgCPM");
        CampaignDataUnionVO.Amount avgCPM = new CampaignDataUnionVO.Amount();
        avgCPM.setAmount(avgCPMObject.get("amount").getAsString());
        avgCPM.setCurrency(avgCPMObject.get("currency").getAsString());
        total.setAvgCPM(avgCPM);
        JsonObject localSpendObject = object.getAsJsonObject("total").getAsJsonObject("localSpend");
        CampaignDataUnionVO.Amount localSpend = new CampaignDataUnionVO.Amount();
        localSpend.setAmount(localSpendObject.get("amount").getAsString());
        localSpend.setCurrency(localSpendObject.get("currency").getAsString());
        total.setLocalSpend(localSpend);
        total.setConversionRate(object.getAsJsonObject("total").get("conversionRate").getAsDouble());
        grandTotals.setTotal(total);
        return grandTotals;
    }

    private List<String> parseStringArray(JsonElement jsonArray) {
        List<String> list = new ArrayList<>();
        for (JsonElement element : jsonArray.getAsJsonArray()) {
            list.add(element.getAsString());
        }
        return list;
    }

    private Map<String, List<String>> parseCountryOrRegionServingStateReasons(JsonObject jsonObject) {
        Map<String, List<String>> map = new HashMap<>();
        for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
            map.put(entry.getKey(), parseStringArray(entry.getValue()));
        }
        return map;
    }

    private CampaignGrandTotalsSaveReqVO getCampaignGrandTotalsReqVO(String date, CampaignDataUnionVO dailyCampaigns) {
        // 将 grandTotals 转换为 CampaignGrandTotalsSaveReqVO
        CampaignGrandTotalsSaveReqVO cgtReqVO = new CampaignGrandTotalsSaveReqVO();
        cgtReqVO.setDate(LocalDate.parse(date));
        cgtReqVO.setGranularity(1); // 假设粒度为1
        cgtReqVO.setImpressions(dailyCampaigns.getGrandTotals().getTotal().getImpressions());
        cgtReqVO.setTaps(dailyCampaigns.getGrandTotals().getTotal().getTaps());
        cgtReqVO.setInstalls(dailyCampaigns.getGrandTotals().getTotal().getInstalls());
        cgtReqVO.setNewDownloads(dailyCampaigns.getGrandTotals().getTotal().getNewDownloads());
        cgtReqVO.setReDownloads(dailyCampaigns.getGrandTotals().getTotal().getRedownloads());
        cgtReqVO.setLatOnInstalls(dailyCampaigns.getGrandTotals().getTotal().getLatOnInstalls());
        cgtReqVO.setLatOffInstalls(dailyCampaigns.getGrandTotals().getTotal().getLatOffInstalls());
        cgtReqVO.setTtr(BigDecimal.valueOf(dailyCampaigns.getGrandTotals().getTotal().getTtr()));
        cgtReqVO.setAvgCpaAmount(new BigDecimal(dailyCampaigns.getGrandTotals().getTotal().getAvgCPA().getAmount()));
        cgtReqVO.setAvgCpaCurrency(dailyCampaigns.getGrandTotals().getTotal().getAvgCPA().getCurrency());
        cgtReqVO.setAvgCptAmount(new BigDecimal(dailyCampaigns.getGrandTotals().getTotal().getAvgCPT().getAmount()));
        cgtReqVO.setAvgCptCurrency(dailyCampaigns.getGrandTotals().getTotal().getAvgCPT().getCurrency());
        cgtReqVO.setAvgCpmAmount(new BigDecimal(dailyCampaigns.getGrandTotals().getTotal().getAvgCPM().getAmount()));
        cgtReqVO.setAvgCpmCurrency(dailyCampaigns.getGrandTotals().getTotal().getAvgCPM().getCurrency());
        cgtReqVO.setLocalSpendAmount(new BigDecimal(dailyCampaigns.getGrandTotals().getTotal().getLocalSpend().getAmount()));
        cgtReqVO.setLocalSpendCurrency(dailyCampaigns.getGrandTotals().getTotal().getLocalSpend().getCurrency());
        cgtReqVO.setConversionRate(BigDecimal.valueOf(dailyCampaigns.getGrandTotals().getTotal().getConversionRate()));

        return cgtReqVO;
    }

    private Map<String, CampaignGrandTotalsSaveReqVO> getCampaignGrandTotalsReqVO(List<CampaignDataSaveReqVO> campaignDataList) {
        // 将 campaignDataList 按日期汇总为 CampaignGrandTotalsSaveReqVO
        Map<String, CampaignGrandTotalsSaveReqVO> dateMap = new HashMap<>();

        for (CampaignDataSaveReqVO data : campaignDataList) {
            if (data == null) {
                continue;
            }
            CampaignGrandTotalsSaveReqVO cgtReqVO = dateMap.getOrDefault(data.getDate().toString(), new CampaignGrandTotalsSaveReqVO());
            cgtReqVO.setDate(data.getDate());

            if (Objects.isNull(data.getImpressions())) {
                continue;
            }

            // 初始化字段值为0
            if (cgtReqVO.getImpressions() == null)
                cgtReqVO.setImpressions(0);
            if (cgtReqVO.getTaps() == null)
                cgtReqVO.setTaps(0);
            if (cgtReqVO.getInstalls() == null)
                cgtReqVO.setInstalls(0);
            if (cgtReqVO.getNewDownloads() == null)
                cgtReqVO.setNewDownloads(0);
            if (cgtReqVO.getReDownloads() == null)
                cgtReqVO.setReDownloads(0);
            if (cgtReqVO.getLatOnInstalls() == null)
                cgtReqVO.setLatOnInstalls(0);
            if (cgtReqVO.getLatOffInstalls() == null)
                cgtReqVO.setLatOffInstalls(0);
            if (cgtReqVO.getTtr() == null)
                cgtReqVO.setTtr(BigDecimal.ZERO);
            if (cgtReqVO.getAvgCpaAmount() == null)
                cgtReqVO.setAvgCpaAmount(BigDecimal.ZERO);
            if (cgtReqVO.getAvgCptAmount() == null)
                cgtReqVO.setAvgCptAmount(BigDecimal.ZERO);
            if (cgtReqVO.getAvgCpmAmount() == null)
                cgtReqVO.setAvgCpmAmount(BigDecimal.ZERO);
            if (cgtReqVO.getLocalSpendAmount() == null)
                cgtReqVO.setLocalSpendAmount(BigDecimal.ZERO);
            if (cgtReqVO.getConversionRate() == null)
                cgtReqVO.setConversionRate(BigDecimal.ZERO);

            cgtReqVO.setOrgId(data.getOrgId());
            cgtReqVO.setAdamId(data.getAdamId());
            cgtReqVO.setImpressions(cgtReqVO.getImpressions() + data.getImpressions());
            cgtReqVO.setTaps(cgtReqVO.getTaps() + data.getTaps());
            cgtReqVO.setInstalls(cgtReqVO.getInstalls() + data.getInstalls());
            cgtReqVO.setNewDownloads(cgtReqVO.getNewDownloads() + data.getNewDownloads());
            cgtReqVO.setReDownloads(cgtReqVO.getReDownloads() + data.getReDownloads());
            cgtReqVO.setLatOnInstalls(cgtReqVO.getLatOnInstalls() + data.getLatOnInstalls());
            cgtReqVO.setLatOffInstalls(cgtReqVO.getLatOffInstalls() + data.getLatOffInstalls());
            cgtReqVO.setTtr(cgtReqVO.getTtr().add(data.getTtr()));
            cgtReqVO.setAvgCpaAmount(cgtReqVO.getAvgCpaAmount().add(data.getAvgCpaAmount()));
            cgtReqVO.setAvgCpaCurrency(data.getAvgCpaCurrency());
            cgtReqVO.setAvgCptAmount(cgtReqVO.getAvgCptAmount().add(data.getAvgCptAmount()));
            cgtReqVO.setAvgCptCurrency(data.getAvgCptCurrency());
            cgtReqVO.setAvgCpmAmount(cgtReqVO.getAvgCpmAmount().add(data.getAvgCpmAmount()));
            cgtReqVO.setAvgCpmCurrency(data.getAvgCpmCurrency());
            cgtReqVO.setLocalSpendAmount(cgtReqVO.getLocalSpendAmount().add(data.getLocalSpendAmount()));
            cgtReqVO.setLocalSpendCurrency(data.getLocalSpendCurrency());
            cgtReqVO.setConversionRate(cgtReqVO.getConversionRate().add(data.getConversionRate()));

            dateMap.put(data.getDate().toString(), cgtReqVO);
        }

        // 计算平均值
        for (Map.Entry<String, CampaignGrandTotalsSaveReqVO> entry : dateMap.entrySet()) {
            CampaignGrandTotalsSaveReqVO cgtReqVO = entry.getValue();

            // 计算 577/5619=0.1027，保留四位小数
            BigDecimal impressions = BigDecimal.valueOf(cgtReqVO.getImpressions());
            BigDecimal taps = BigDecimal.valueOf(cgtReqVO.getTaps());
            BigDecimal installs = BigDecimal.valueOf(cgtReqVO.getInstalls());
            BigDecimal localSpendAmount = cgtReqVO.getLocalSpendAmount();

            BigDecimal ttr = cgtReqVO.getTaps() > 0 ? taps.divide(impressions, 4, RoundingMode.HALF_UP) : BigDecimal.ZERO;
            BigDecimal conversionRate = cgtReqVO.getInstalls() > 0 ? installs.divide(taps, 4, RoundingMode.HALF_UP) : BigDecimal.ZERO;
            cgtReqVO.setTtr(ttr);
            cgtReqVO.setConversionRate(conversionRate);

            cgtReqVO.setAvgCptAmount(cgtReqVO.getTaps() > 0 ? localSpendAmount.divide(taps, 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            cgtReqVO.setAvgCpaAmount(cgtReqVO.getInstalls() > 0 ? localSpendAmount.divide(installs, 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);

            // 计算 localSpendAmount/impressions*1000 250.13/5619*1000=44.515
            BigDecimal avgCpmAmount = cgtReqVO.getImpressions() > 0 ? localSpendAmount.divide(impressions, 5, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(1000)) : BigDecimal.ZERO;
            cgtReqVO.setAvgCpmAmount(avgCpmAmount);
        }

        return dateMap;
    }

    private @NotNull List<CampaignDataSaveReqVO> getCampaignDataReqVOS(CampaignDataUnionVO dailyCampaigns) {
        // 将 rows 转换为 List<CampaignDataDO>
        return dailyCampaigns.getRow().stream()
                .flatMap(row -> row.getGranularity().stream().map(granularity -> {
                    CampaignDataSaveReqVO campaignDataDO = new CampaignDataSaveReqVO();
                    campaignDataDO.setDate(LocalDate.parse(granularity.getDate()));
                    campaignDataDO.setCountryOrRegion(row.getMetadata().getCountryOrRegion());
                    if (granularity.getImpressions() == 0) {
                        return null;
                    }
                    campaignDataDO.setImpressions(granularity.getImpressions());
                    campaignDataDO.setTaps(granularity.getTaps());
                    campaignDataDO.setInstalls(granularity.getInstalls());
                    campaignDataDO.setNewDownloads(granularity.getNewDownloads());
                    campaignDataDO.setReDownloads(granularity.getRedownloads());
                    campaignDataDO.setLatOnInstalls(granularity.getLatOnInstalls());
                    campaignDataDO.setLatOffInstalls(granularity.getLatOffInstalls());
                    campaignDataDO.setTtr(BigDecimal.valueOf(granularity.getTtr()));
                    campaignDataDO.setAvgCpaAmount(new BigDecimal(granularity.getAvgCPA().getAmount()));
                    campaignDataDO.setAvgCpaCurrency(granularity.getAvgCPA().getCurrency());
                    campaignDataDO.setAvgCptAmount(new BigDecimal(granularity.getAvgCPT().getAmount()));
                    campaignDataDO.setAvgCptCurrency(granularity.getAvgCPT().getCurrency());
                    campaignDataDO.setAvgCpmAmount(new BigDecimal(granularity.getAvgCPM().getAmount()));
                    campaignDataDO.setAvgCpmCurrency(granularity.getAvgCPM().getCurrency());
                    campaignDataDO.setLocalSpendAmount(new BigDecimal(granularity.getLocalSpend().getAmount()));
                    campaignDataDO.setLocalSpendCurrency(granularity.getLocalSpend().getCurrency());
                    campaignDataDO.setConversionRate(BigDecimal.valueOf(granularity.getConversionRate()));
                    campaignDataDO.setCampaignId(row.getMetadata().getCampaignId());
                    campaignDataDO.setCampaignName(row.getMetadata().getCampaignName());
                    campaignDataDO.setIsDeleted(row.getMetadata().isDeleted());
                    campaignDataDO.setCampaignStatus(row.getMetadata().getCampaignStatus());
                    campaignDataDO.setAppName(row.getMetadata().getApp().getAppName());
                    campaignDataDO.setAdamId(row.getMetadata().getApp().getAdamId());
                    campaignDataDO.setServingStatus(row.getMetadata().getServingStatus());
                    campaignDataDO.setCountriesOrRegions(String.join(",", row.getMetadata().getCountriesOrRegions()));
                    campaignDataDO.setModificationTime(LocalDateTime.parse(row.getMetadata().getModificationTime()));
                    campaignDataDO.setDailyBudgetAmount(Double.parseDouble(row.getMetadata().getDailyBudget().getAmount()));
                    campaignDataDO.setDailyBudgetCurrency(row.getMetadata().getDailyBudget().getCurrency());
                    campaignDataDO.setDisplayStatus(row.getMetadata().getDisplayStatus());
                    campaignDataDO.setSupplySources(String.join(",", row.getMetadata().getSupplySources()));
                    campaignDataDO.setAdChannelType(row.getMetadata().getAdChannelType());
                    campaignDataDO.setOrgId(row.getMetadata().getOrgId());
                    campaignDataDO.setBillingEvent(row.getMetadata().getBillingEvent());
                    return campaignDataDO;
                }))
                .collect(Collectors.toList());
    }
}